using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 笔记：为什么不使用单例模式而使用IOC容器呢，IOC容器涉及Dictionary操作，相比单例模式损耗更多性能，所以这样做的目的是什么呢？
// 答案：使用IOC容器目的仅仅是为了增加模块的访问限制。例如，模块的获取必须通过项目的Architecture类进行，CounterApp和PointGame类就可以说明这一点。当然，引入了IOC之后，还可以增加更多的限制。
// IOC容器还有没有其它好处？当然，我们在统一的地方去注册模块，这样更有利于让开发人员拥有宏观的视角，而统一注册模块的地方可以充当一个“架构草图”，省去了维护一个“架构草图”的麻烦。
// 另外，IOC容器的更多好处还有更符合SOLID原则、有更好的纸上设计体验、可以增加层级、增加中间件模式、增加事件中心等等。

namespace FrameworkBase
{
    public interface IArchitecture
    {
        /// <summary>
        /// 注册系统
        /// </summary>
        void RegisterSystem<T>(T system) where T : ISystem;
        /// <summary>
        /// 注册 Model
        /// </summary>
        /// <param name="model"></param>
        /// <typeparam name="T"></typeparam>
        void RegisterModel<T>(T model) where T : IModel;
        /// <summary>
        /// 注册 Utility
        /// </summary>
        /// <param name="utility"></param>
        /// <typeparam name="T"></typeparam>
        void RegisterUtility<T>(T utility);

        /// <summary>
        /// 获取 Model
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetModel<T>() where T : class, IModel;
        /// <summary>
        /// 获取工具
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T GetUtility<T>() where T : class;
    }
    
    public abstract class Architecture<T> : IArchitecture where T : Architecture<T>, new()
    {
        /// <summary>
        /// 是否初始化完成
        /// </summary>
        private bool _inited = false;

        private List<ISystem> _systems = new List<ISystem>();
        private List<IModel> _models = new List<IModel>();

        public static Action<T> OnRegisterPatch = architecture => { };

        private static T _architecture;

        public static IArchitecture Instance
        {
            get
            {
                if (_architecture == null)
                {
                    MakeSureArchitecture();
                }

                return _architecture;
            }
        }

        // 确保 Container 是有实例的
        static void MakeSureArchitecture()
        {
            if (_architecture == null)
            {
                _architecture = new T();
                _architecture.Init();

                // 调用
                OnRegisterPatch?.Invoke(_architecture);

                // 初始化 Model
                foreach (var architectureModel in _architecture._models)
                {
                    architectureModel.Init();
                }

                // 清空 Model
                _architecture._models.Clear();
                
                // 初始化 System
                foreach (var architectureSystem in _architecture._systems)
                {
                    architectureSystem.Init();
                }

                // 清空 System
                _architecture._systems.Clear();
                
                _architecture._inited = true;
            }
        }

        // 留给子类注册模块
        protected abstract void Init();

        private IOCContainer _container = new IOCContainer();
        
        // 提供一个注册模块的 API
        public static void Register<T>(T instance)
        {
            MakeSureArchitecture();

            _architecture._container.Register<T>(instance);
        }

        public void RegisterSystem<T>(T system) where T : ISystem
        {
            system.SetArchitecture(this);
            _container.Register<T>(system);

            if (!_inited)
            {
                _systems.Add(system);
            }
            else
            {
                system.Init();
            }
        }

        public void RegisterModel<T>(T model) where T : IModel
        {
            model.SetArchitecture(this);
            _container.Register<T>(model);

            if (!_inited)
            {
                _models.Add(model);
            }
            else
            {
                model.Init();
            }
        }

        public void RegisterUtility<T>(T utility)
        {
            _container.Register<T>(utility);
        }
        public static T Get<T>() where T : class
        {
            MakeSureArchitecture();
            return _architecture._container.Get<T>();
        }

        public T GetModel<T>() where T : class, IModel
        {
            return _container.Get<T>();
        }

        // 提供一个获取模块的 API

        public T GetUtility<T>() where T : class
        {
            return _container.Get<T>();
        }
    }
}